home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Communication / LibraryOfCongress / Source / Storm.m < prev    next >
Text File  |  1994-05-23  |  16KB  |  688 lines

  1. /*
  2.  * Interface for network Library of Congress search service.
  3.  *
  4.  * Michael Hawley
  5.  * MIT Media Laboratory
  6.  * 20 Ames Street
  7.  * Cambridge, MA 02139
  8.  * mike@media-lab.mit.edu
  9.  * Copyright (c) 1991 MIT Media Laboratory
  10.  * Burn before reading!  This means you!!
  11.  *
  12.  * Please forward any comments/revisions.
  13.  */
  14.  
  15. #import "Storm.h"
  16. #import "Process.h"
  17. #import <appkit/appkit.h>
  18. #import "MyMenuCell.h"
  19. #import "Defaults.h"
  20. #import "util.h"
  21.  
  22. @implementation Storm
  23.  
  24. int StormDebug = 1;
  25. id _status;
  26. id _PutHere;
  27. extern setState(), ReadState(), runState(), access(), 
  28.        getReport(), sleep(), execState();
  29.  
  30. int confirm(a,b,c,d) char *a,*b,*c,*d; {
  31.     char t[1024];
  32.     sprintf(t,a,b,c,d);
  33.     return NXRunAlertPanel([NXApp appName],t,"Yes","No",NULL)==1;
  34. }
  35.  
  36. char *
  37. path(char *s)
  38. /*
  39.  * if 's' is in [NXArgv[0]], return [NXArgv[0]]/s.
  40.  * (for looking up internal commands and files in .../Opener.app/...).
  41.  */
  42. {
  43.     char t[1024], *q, *r;
  44.     static char p[1024];
  45.     extern char **NXArgv;
  46.     *t = '\0';
  47.     sscanf(s,"%s",t);
  48.     if (!*t || *t=='(') return s;
  49.     r = s + strlen(t);
  50.     strcpy(p,*NXArgv);
  51.     if (q=rindex(p,'/'))
  52.         strcpy(q+1,t);
  53.     else
  54.         strcpy(p,t);
  55.     if (access(p,0)==0){
  56.         strcpy(p+strlen(p),r);
  57.         return p;
  58.     }
  59.     return s;
  60. }
  61.  
  62. static void say(s, a,b,c,d) id s; char *a,*b,*c,*d; {
  63.     char p[1024];
  64.     sprintf(p,a,b,c,d);
  65.     [s setStringValue:p];
  66.     [s display];
  67.     NXPing();
  68. }
  69.  
  70. void message(a,b,c,d) char *a,*b,*c,*d; {
  71.     say(_status,a,b,c,d);
  72. }
  73.  
  74. /*
  75.  * These two routines are for tracking net activity.
  76.  */
  77. static void
  78. monitorMail(subj,body,dest) char *subj, *body, *dest; {
  79.     char s[1024];
  80.     if (!dest || !*dest) dest = "monitor@tome.media.mit.edu";
  81.     if (body && *body) sprintf(s,"echo %s",body);
  82.     else strcpy(s,"(whoami ; hostname)");
  83.     sprintf(s+strlen(s),"| /usr/ucb/Mail -s \"%s\" %s &",
  84.     subj && *subj? subj : [NXApp appName], dest);
  85.     system(s);
  86. }
  87.  
  88.  
  89. static int eq(char *a, char *b){ return strncmp(a,b,strlen(b))==0; }
  90.  
  91.  
  92. static void put(P, fmt, a, b, c, d) id P; char *fmt, *a, *b, *c, *d; {
  93.     char p[1024];
  94.     sprintf(p,fmt,a,b,c,d);
  95.     if (Verbose) printf("+ %s\n",p);
  96.     [P puts:p]; 
  97. }
  98.  
  99. void Put(fmt, a, b, c, d) char *fmt, *a, *b, *c, *d; {
  100.     put(_PutHere,fmt,a,b,c,d);
  101. }
  102.  
  103.  
  104. static char *
  105. get(P, s, n) id P; char *s; int n; {
  106.     [P gets:s:n];
  107.     if (*s && Verbose) printf("> %s",s);
  108.     return *s? s : (char *)0; 
  109. }
  110.  
  111. char *
  112. pgets(s,n) char *s; int n; {
  113.     [_PutHere gets:s:n];
  114.     cleanEsc(s);
  115.     return *s? s : (char *)0; 
  116. }
  117.  
  118. char *
  119. pgetsx(s,n) char *s; int n; {
  120.     [_PutHere gets:s:n];
  121.     return *s? s : (char *)0; 
  122. }
  123.  
  124. char
  125. pgetc() {
  126.     char c = [_PutHere getc];
  127.     if (c == 27 || c== '['){
  128.         while ((c = [_PutHere getc]) != 'H' /* && c != 'm'*/ && c != '\n' && c != '\r') ;
  129.         if (c=='H' || c=='m') c = [_PutHere getc];
  130.     }
  131.     return c;
  132. }
  133.  
  134. /***
  135. #ifdef 0
  136. static char *
  137. flush(P,s) id P; char *s; {
  138.     static char t[1024];
  139.     while (get(P,t,sizeof t))
  140.         if (strindex(t,s)) return t;
  141.     sleep(1);
  142.     while (get(P,t,sizeof t))
  143.         if (strindex(t,s)) return t;
  144.     return (char *)0;
  145. }
  146. #endif
  147. ***/
  148.  
  149. char *
  150. Flush(s) char *s; {
  151.     static char t[1024];
  152.     if (_PutHere) return (char *)0;
  153.     while (get(_PutHere,t,sizeof t))
  154.         if (strindex(t,s)) return t;
  155.     sleep(1);
  156.     while (get(_PutHere,t,sizeof t))
  157.         if (strindex(t,s)) return t;
  158.     return (char *)0;
  159. }
  160.  
  161. - enable:(BOOL)b {
  162.     [attachB setIcon:b? "plug" : "unplug"];
  163.     return self;
  164. }
  165.  
  166. static id _text, _scroll;
  167.  
  168. - initMatrix {
  169.     // from the nib file, we have the help text; keep a pointer to it.
  170.     _text = helpText = [scrollView docView];
  171.     [_text setDelegate:self];
  172.     [_text setMarginLeft:6.0 right:6.0 top:0.0 bottom:0.0];
  173.     [_text notifyAncestorWhenFrameChanged:YES];
  174.     return self;
  175. }
  176.  
  177. - setScrollView:anObject {
  178.     _scroll = scrollView = anObject;
  179.     [self initMatrix];
  180.     return self;
  181. }
  182.  
  183. extern char DefaultFont[];
  184. extern char DefaultFontSize[];
  185. static id fid = (id)0;
  186. static int canconvert = 0;
  187. // double atof();
  188. char TextBuf[80000]="";
  189.  
  190. #import <appkit/FontManager.h>
  191.  
  192. prettyFormat(s) char *s; { // tweak fonts in a card catalog record
  193.     char *p = index(s,'\n')+1;
  194.     if (*s){ // italicize leading ...: fields
  195.       char *q = index(p,':');
  196.  
  197.       while (q && *q == ':'){
  198.           [_text setSel:p-s:q-s+1];
  199.           [_text setSelFontSize:[fid pointSize]*(12./14.)];
  200.           [_text setSelFontStyle:NX_ITALIC];
  201.           p = index(q,'\n'); if (p) p++;
  202.           if (p && *p) q = index(p,':');
  203.           else q = (char *)0;
  204.       }
  205.     }
  206. }
  207.  
  208. /*
  209.  * This is called as a TimedEntry as a kludge -- the effect we want
  210.  * is for the user to change the font in the text view, and then to
  211.  * apply the prettyFormat() to it.  The problem is that textWillConvert
  212.  * will be invoked for every font change and we want to do this
  213.  * after the smoke has cleared.
  214.  */
  215. hackToEnforceFonts(DPSTimedEntry n, double now, char *userData) {
  216.     if (canconvert && *TextBuf){ // reformat current entry
  217.     id w = [_scroll window];
  218.     char *s = TextBuf, *p = index(s,'\n')+1;
  219.     static NXPoint origin = {0.0,0.0};
  220.         DPSRemoveTimedEntry(n);
  221.     canconvert=0;
  222.     [w disableFlushWindow];
  223.     //[_text setText:s];
  224.     [_text setSel:p-s:strlen(s)];
  225.     [_text setSelGray:0.0];
  226.     [_text setSelFont:fid];
  227.  
  228.     prettyFormat(s);
  229.  
  230.     [_text selectNull];
  231.     [_text scrollPoint:&origin];
  232.     [_scroll display];
  233.     [[w reenableFlushWindow] flushWindow];
  234.     canconvert=1;
  235.         [_text setDelegate:userData];
  236.     }
  237. }
  238.  
  239. - textWillConvert:textObject fromFont:from toFont:to {
  240.     if (canconvert && (strcmp(DefaultFont,[from name])==0 ||
  241.     atof(DefaultFontSize) == [from pointSize])){
  242.     strcpy(DefaultFont,[to name]);
  243.     sprintf(DefaultFontSize,"%f",[to pointSize]);
  244.     fid = to;
  245.         writeDefaults();
  246.         [_text setDelegate:0];
  247.         DPSAddTimedEntry(0.,hackToEnforceFonts,self,100);
  248.     }
  249.     return to;
  250. }
  251.  
  252. void
  253. setText(s) char *s; {
  254.     static NXPoint origin = {0.0,0.0};
  255.     char *p = index(s,'\n')+1;  /* skip past first (blank) line */
  256.     id w = [_scroll window];
  257.  
  258.     if (!fid){
  259.         fid = [Font newFont:DefaultFont size:atof(DefaultFontSize)];
  260.     }
  261.     canconvert=0;
  262.     [w disableFlushWindow];
  263.     [_text setText:s];
  264.     [_text setSel:p-s:strlen(s)];
  265.     [_text setSelGray:0.0];
  266.     [_text setSelFont:fid];
  267.  
  268.     prettyFormat(s);
  269.  
  270.     [_text selectNull];
  271.     [_text scrollPoint:&origin];
  272.     [_scroll display];
  273.     [[w reenableFlushWindow] flushWindow];
  274.  
  275.     canconvert=1;
  276.     strcpy(TextBuf,s);
  277.  
  278.       if (TextBuf[0] && index(TextBuf,':')) [[_text delegate] enableOrder];
  279.       else [[_text delegate] disableOrder];
  280. }
  281.  
  282. void
  283. setFile(s) char *s; {
  284.     NXStream *f = NXMapFile(path(s),NX_READONLY);
  285.     static NXPoint origin = {0.0,0.0};
  286.     id w = [_scroll window];
  287.  
  288.     canconvert=0;
  289.     s = path(s);
  290.     if (!f) return ;
  291.     [w disableFlushWindow];
  292.     [_text setMonoFont:NO];
  293.     [_text readRichText:f];
  294.     [_text scrollPoint:&origin];
  295.     NXCloseMemory(f,NX_FREEBUFFER);
  296.     [_scroll display];
  297.     [[w reenableFlushWindow] flushWindow];
  298.     TextBuf[0] = '\0';
  299.     [[_text delegate] disableOrder];
  300. }
  301.  
  302. - showHelp:sender {
  303.     setFile("info");
  304.     return self;
  305. }
  306.  
  307. #define Case break; case
  308.  
  309. void
  310. squishRtn(char *s){
  311.     char *p = s;
  312.  
  313.     while (*p = *s++)
  314.         if (*p != '\r') ++p;
  315. }
  316.  
  317. static char *
  318. getLine(char *s, char *t){ /* read ...\n from s into t; return new s */
  319.     char *p = t;
  320.     *t = '\0';
  321.     squishRtn(s);
  322.     while (*s && *s != '\n') *p++ = *s++;
  323.     if (*s == '\n') *p++ = *s++;
  324.     *p++ = '\0';
  325.     if (*t == '\0') return (char *)0;
  326.     p = t;
  327.     return s;
  328. }
  329.  
  330. cleanEsc(s) char *s; {
  331.     if (*s == '[' || *s == 27){
  332.         char *p = s;
  333.         while (*p && *p != '\n' && *p != 'H') ++p;
  334.         if (*p == 'H') ++p;
  335.         strcpy(s,p);
  336.     }
  337.     return 1;
  338. }
  339.  
  340. - processOutput:(char *)s {
  341.     static char prev[8192]="";
  342.     char t[1024], *p=prev;
  343.     {
  344.         char *p = s;
  345.         while (*p){
  346.             if (*p == 27) *p = '\n';
  347.             p++;
  348.         }
  349.     }
  350.     strcat(prev,s); s = t;
  351.     while ((p=getLine(p,s)) && 
  352.            (index(s,'\n') && cleanEsc(s))){
  353.         if (Verbose) printf("- %s",s);
  354.         execState(0,s);
  355.     }
  356.     strcpy(prev,blank(s)?s:"");
  357.     return self;
  358. }
  359.  
  360. - hitFormat:sender {
  361.     extern setFormat();
  362.     extern char *cmdHelpText();
  363.     char *s = (char *)[[sender selectedCell] title];
  364.     setFormat(s);
  365.     [cmdHelp setStringValue:cmdHelpText()];
  366.     return self;
  367. }
  368.  
  369. id _browser;
  370.  
  371. - query:sender {
  372.     char buf[80000];
  373.     extern int LastItem;
  374.     char *fixQuery(), *s = fixQuery([form stringValueAt:0]);
  375.     if (!s || !*s){ // beep
  376.         return self;
  377.     }
  378.     _browser = browser;
  379.     enableMore(0);
  380.     resetItems(); [browser loadColumnZero];
  381.     Put("%s\r",s); pgets(buf,256);
  382.     getReport(buf,0);
  383.     [browser loadColumnZero];
  384.     [form selectTextAt:0];
  385.     if (LastItem == 3){
  386.         fixItem(buf);
  387.         setText(buf);
  388.     } else
  389.         setText("");
  390.     return self;
  391. }
  392.  
  393. static id me;
  394.  
  395. void
  396. Command(s) char *s; {
  397.     _PutHere = [Process new:s delegate:me];
  398. }
  399.  
  400. - click:sender {
  401.     id c =  [[browser matrixInColumn:[browser lastColumn]] selectedCell];
  402.     if ([c isLeaf])
  403.         [c click:self];
  404.     return self;
  405. }
  406.  
  407. reload(DPSTimedEntry n, double now, char *userData) {
  408.     extern int MustReload;
  409.     DPSRemoveTimedEntry(n);
  410.     if (MustReload) [_browser loadColumnZero], MustReload = 0;
  411.     setText("");
  412. }
  413.  
  414. - (int)browser:sender fillMatrix:matrix inColumn:(int)column {
  415.     extern int NI;
  416.     return NI;
  417. }
  418.  
  419. - browser:sender loadCell:c atRow:(int)row inColumn:(int)column {
  420.     [c setContents:row];
  421.     return self;
  422. }
  423.  
  424. id _moreB;
  425.  
  426. - more:sender {
  427.     extern int LastItem;
  428.     char buf[80000];
  429.     Put("n\r"); pgets(buf,256);
  430.     getReport(buf,1);
  431.     [browser loadColumnZero];
  432.     [form selectTextAt:0];
  433.     if (LastItem == 3){
  434.         fixItem(buf);
  435.         setText(buf);
  436.     } else
  437.         setText("");
  438.     return self;
  439. }
  440.  
  441. enableMore(n){
  442.     return [_moreB setEnabled:n];
  443. }
  444.  
  445. - login:sender {
  446.     if (_PutHere) [_PutHere free]; P = _PutHere = (id)0;
  447.     _status = status;
  448.     _moreB = moreB;
  449.     ReadState(path("menus"));
  450.     [browser setDelegate:self];
  451.     [browser setCellPrototype:[[MyMenuCell alloc] init]];
  452.     [browser setAction:@selector(click:)];
  453.     [browser setTarget:self];
  454.     [attachB setIcon:"plug"];
  455.     [form selectTextAt:0];
  456.     runState("");
  457.     return self;
  458. }
  459.  
  460. - ready:sender {
  461.     resetItems(); [browser loadColumnZero];
  462.     [searchB setEnabled:1];
  463.     return self;
  464. }
  465.  
  466. - logout:sender {
  467.     if (P && _PutHere) setState("Detach"), runState("");
  468.     if (P) [P terminate:self];
  469.     _PutHere = P = (id)0;
  470.     [self enable:NO];
  471.     [attachB setIcon:"unplug"];
  472.     [searchB setEnabled:0];
  473.     message("not connected.");
  474.     return self;
  475. }
  476.  
  477. void
  478. ready(){
  479.     [me ready:me];
  480. }
  481.  
  482. void
  483. logout(){
  484.     [me logout:me];
  485. }
  486.  
  487. - ensurelogin {
  488.     //if (!_PutHere) [self login:self];
  489.     return self;
  490. }
  491.  
  492. int
  493. ensurelogin(){
  494.     [me ensurelogin];
  495.     return _PutHere? 1 : 0;
  496. }
  497.  
  498. - attach:sender {
  499.     if (eq((char *)[sender icon],"unplug")){
  500.         [self login:sender];
  501.     } else {
  502.         [self logout:sender];
  503.     }
  504.     return self;
  505. }
  506.  
  507. /*
  508.  * telnet:
  509.  */
  510. - copyString:(char *)s {
  511.   id p = [Pasteboard new];
  512.   [p declareTypes:&NXAsciiPboard num:1 owner:self];
  513.   [p writeType:NXAsciiPboard data:s length:strlen(s)];
  514.   return self;
  515. }
  516.  
  517. - launchTerminal:(char *)program {
  518.   id p = [NXApp appSpeaker];
  519.   port_t t = NXPortFromName("Terminal",NULL);
  520.   int ok;
  521.   if (t==PORT_NULL) return self;
  522.   [p setSendPort:t];
  523.   [self copyString:program];
  524.   (void)[p msgPaste:&ok];
  525.   return self;
  526. }
  527.  
  528. - (char *)service {
  529.     char *s = "dra.com"; // (char *)[[format selectedCell] title];
  530.     return s && *s? s : "192.65.218.43";
  531. }
  532.  
  533. - telnet:sender {
  534.     char s[1024];
  535.     sprintf(s,"telnet %s\n", [self service]);
  536.     [self launchTerminal:s];
  537.     return self;
  538. }
  539.  
  540. - sendComments:sender {
  541.     return self;
  542. }
  543.  
  544. char *
  545. orderForm(){
  546.     static char s[1024]="";
  547.     char *h;
  548.     if (*s) return s;
  549.     h = getenv("HOME");
  550.     if (!h || !*h) sprintf(s,"/tmp");
  551.     else sprintf(s,"%s/.NeXT",h);
  552.     strcat(s,"/BookOrderForm");
  553. }
  554.  
  555. - editOrder:sender {
  556.     if (access(orderForm(),0)){
  557.         System("cp %s %s",path("BookOrderForm"),orderForm());
  558.     }
  559.     System("open %s",orderForm());
  560.     return self;
  561. }
  562.  
  563. - enableOrder {
  564.     [orderB setEnabled:YES];
  565.     [orderMenuB setEnabled:YES];
  566.     return self;
  567. }
  568.  
  569. - disableOrder {
  570.     [orderB setEnabled:NO];
  571.     [orderMenuB setEnabled:NO];
  572.     return self;
  573. }
  574.  
  575. - sendOrder:sender {
  576.     char t[1024],t2[1024],body[80000], *Body = body;
  577.     char to[1024] = "", cc[1024]="", subj[1024]="";
  578.     FILE *f;
  579. #define fcall(a)  [s performRemoteMethod:a]
  580. #define call(a,b) [s performRemoteMethod:a with:b length:strlen(b)+1]
  581.     id s = [NXApp appSpeaker];
  582.  
  583.     if (access(orderForm(),0)){
  584.         if (confirm("You need to edit the order form...")){
  585.             [self editOrder:self];
  586.             //monitorMail("LibraryOfCongress-1.0-order",0,0);
  587.         }
  588.         return self;
  589.     }
  590.  
  591.     strcpy(to,"quanbook@world.std.com");
  592.     strcpy(subj,"another e-mail book order");
  593.     strcpy(cc,"whoami"); execstr(cc); stripnl(cc);
  594.  
  595.     *body = '\0';
  596.     if (strindex(TextBuf,"Type of Material:")){
  597.         char *p, c[1024], t[80000];
  598.     sprintf(t, "/tmp/book-order%d",getpid());
  599.     sprintf(t2,"/tmp/book-info%d",getpid());
  600.     System("sed '/^#/d' %s > %s",orderForm(),t);
  601.     f = fopen(t2,"w");
  602.     if (!f){
  603.         confirm("Couldn't create scratch file (%s)",t2);
  604.     } else {
  605.         write(fileno(f),TextBuf,strlen(TextBuf));
  606.         write(fileno(f),"Body:\n",6);
  607.             //strcpy(t,TextBuf+1); sub(t,'\t',' ');
  608.         write(fileno(f),TextBuf+1,strlen(TextBuf+1));
  609.         write(fileno(f),"Body:\n",6);
  610.         fclose(f);
  611.     }
  612.         sprintf(c,"sed '/^[a-zA-Z]* [a-zA-Z ]*:/s/ /_/' %s > %sa",t2,t2);
  613.         system(c);
  614.         sprintf(c,"%s %s < %sa > %sa",path("rtfcast"),t,t2,t);
  615.         system(c);
  616.         unlink(t); unlink(t2); strcat(t,"a"); strcat(t2,"a");
  617.         f = fopen(t,"r");
  618.     if (!f){
  619.         confirm("Couldn't read scratch file (%s)",t);
  620.     } else {
  621.         int n = read(fileno(f),body,sizeof(body));
  622.         if (n > 0) body[n] = '\0';
  623.             fclose(f);
  624.     }
  625.         unlink(t); unlink(t2);
  626.         if (((p = strindex(Body,"To:")) ||
  627.              (p = strindex(Body,"to:"))) &&
  628.              (p == Body || p[-1] == '\n')){
  629.             sscanf(skipsp(index(p,':')+1),"%[^\n]",to);
  630.             if (p==Body) Body = index(p,'\n')+1;
  631.         }
  632.         if (((p = strindex(Body,"Subject:")) ||
  633.              (p = strindex(Body,"subject:"))) &&
  634.              (p == Body || p[-1] == '\n')){
  635.             sscanf(skipsp(index(p,':')+1),"%[^\n]",subj);
  636.             if (p==Body) Body = index(p,'\n')+1;
  637.         }
  638.         if (((p = strindex(Body,"Cc:")) ||
  639.              (p = strindex(Body,"cc:"))) &&
  640.              (p == Body || p[-1] == '\n')){
  641.             sscanf(skipsp(index(p,':')+1),"%[^\n]",cc);
  642.             if (p==Body) Body = index(p,'\n')+1;
  643.         }
  644.     }
  645.  
  646.     NXPortFromName("Mail", NULL); // make sure app is launched
  647.     [s setSendPort:NXPortFromName("MailSendDemo", NULL)];
  648.  
  649.     call("setTo:",to);
  650.     call("setSubject:",subj);
  651.     call("setCc:",cc);
  652.     call("setBody:",Body);
  653.     
  654.     return self;
  655. }
  656.  
  657. - print:sender {
  658.     [_text printPSCode:sender];
  659.     return self;
  660. }
  661.  
  662. + new {
  663.     me = self = [[Storm alloc] init];
  664.     return self;
  665. }
  666.  
  667. - free {
  668.     [self logout:self];
  669.     return [super free];
  670. }
  671.  
  672. - appDidInit:sender {
  673.     openDefaults();
  674.     if (FirstUse()) [license show:self],
  675.                     strcpy(DefaultFont,"Helvetica-Bold"),
  676.                     strcpy(DefaultFontSize,"18.0");
  677.     [attachB performClick:sender];
  678.     return self;
  679. }
  680.  
  681. - appWillTerminate:sender {
  682.     [self logout:self];
  683.     writeDefaults();
  684.     return self;
  685. }
  686.  
  687. @end
  688.